/**
 * @brief 
 * @param
 * @return none
 **/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#define GPIO_INPUT_IO_0     (5)
#define GPIO_INPUT_IO_1     (7)
#define GPIO_INPUT_PIN_SEL  ((1ULL<<GPIO_INPUT_IO_0) | (1ULL<<GPIO_INPUT_IO_1))
/*
 * Let's say, GPIO_INPUT_IO_0=5, GPIO_INPUT_IO_1=7
 * In binary representation,
 * 1ULL<<GPIO_INPUT_IO_0 is equal to 0000000000000000000000000000000000010000 and
 * 1ULL<<GPIO_INPUT_IO_1 is equal to 0000000000000000000000000000000000100000
 * GPIO_INPUT_PIN_SEL                0000000000000000000000000000000000110000
 * */
#define ESP_INTR_FLAG_DEFAULT 0
//中断计数变量（调试）
volatile int enter_isr_cnt4=0;
//消息队列
static QueueHandle_t gpio_evt_queue4= NULL;
/**
 * @brief GPIO中断服务服务函数,
 *        终端发生时，向gpio_evt_queue4队列发送数据,gpio_task_example中接收
 *        队列设置的很小只有一个元素，目的是消除抖动
 * @return none
 **/
static void IRAM_ATTR gpio_isr_handler4(void* arg)
{
    uint32_t gpio_num = (uint32_t) arg;
    xQueueSendFromISR(gpio_evt_queue4, &gpio_num, NULL);
    //中断计数变量（调试）
    enter_isr_cnt4++;
}

/**
 * @brief 同上
 * @param
 * @return none
 **/
volatile int enter_isr_cnt7=0;
static QueueHandle_t gpio_evt_queue7= NULL;
static void IRAM_ATTR gpio_isr_handler7(void* arg)
{
    uint32_t gpio_num = (uint32_t) arg;
    xQueueSendFromISR(gpio_evt_queue7, &gpio_num, NULL);
    enter_isr_cnt7++;
}


//按键gpio也和串口用同一个队列( 这里将外部中断等事件，统一用串口数据来表示 )
extern QueueHandle_t uart_to_udp_queue;
char* teststr_1="CONTROL-key1";// 模拟串口数据，表示key1按下，表示“ctrl+c 复制”(可用上位机的excel改变该键值定义)
char* teststr_2="CONTROL-key2";// 模拟串口数据，表示key2按下表示粘贴“ctrl+v 粘贴”
// 定义一个变量来记录上次检测到的按键状态
volatile int last_button_state = 0;
#define DEBOUNCE_DELAY_MS  50
//pin4_pressed、pin7_pressed 按键计数变量（调试）,区别于enter_isr_cnt4
int static  pin4_pressed = 0;
int static  pin7_pressed = 0;
/**
 * @brief 按键检测任务：
 *        接收来自于GPIO中断的信号队列，然后通过xQueueSend(),将数据写入uart_to_udp_queue队列,等待udp_client_task的接收
 *        如果GPIO4检测到中断，则向队列写入"CONTROL-key1"，
 *        如果GPIO7检测到中断，则向队列写入"CONTROL-key2"
 * @param
 * @return none
 **/
static void gpio_task_example(void* arg)
{
    uint32_t io_num;
    uint32_t delay_tick=1 / portTICK_PERIOD_MS;
    for (;;) {
       vTaskDelay(50 / portTICK_PERIOD_MS);//延时50ms
       io_num=0;
       if (xQueueReceive(gpio_evt_queue4, &io_num, delay_tick)==pdTRUE) 
        {
            pin4_pressed++;
            vTaskDelay(150 / portTICK_PERIOD_MS);
            xQueueReset( gpio_evt_queue4 );
           //将外部中断等事件，统一用串口数据来表示，比如这里接收到gpio4的中断,就等于串口接收到命令"CONTROL-key1"
           if (xQueueSend(uart_to_udp_queue,&teststr_1, portMAX_DELAY) == pdPASS)
           {
               // ESP_LOGI(TAG, "Data sent to UDP task");
           }    
            //printf("GPIO[%"PRIu32"] intr, val: %d-   pressed：%d\n", io_num, gpio_get_level(io_num),is_pressed++);
        }
        
        io_num=0;
        if (xQueueReceive(gpio_evt_queue7, &io_num, delay_tick)==pdTRUE) 
        {
            pin7_pressed++;
            vTaskDelay(150 / portTICK_PERIOD_MS);
            xQueueReset( gpio_evt_queue7 );
            
        }
    }

}

void Button_Gpio_Init(void)
{
    gpio_config_t io_conf = {};
   /*-------------输入相关GPIO----------------*/
    io_conf.intr_type = GPIO_INTR_POSEDGE;
    //bit mask of the pins, use GPIO4/7 here
    io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
    //set as input mode
    io_conf.mode = GPIO_MODE_INPUT;
    //enable pull-up mode
   // io_conf.pull_up_en = 1;//不要上拉
    gpio_config(&io_conf);
   // gpio_set_intr_type(GPIO_INPUT_IO_0, GPIO_INTR_POSEDGE);
   /*-------------下降沿触发中断---------------*/
    gpio_set_pull_mode(GPIO_INPUT_IO_0, GPIO_FLOATING);
    gpio_set_pull_mode(GPIO_INPUT_IO_1, GPIO_FLOATING);
    /*----------------------------*/
    //create a queue to handle gpio event from isr
    gpio_evt_queue4 = xQueueCreate(1, sizeof(uint32_t));
    gpio_evt_queue7 = xQueueCreate(1, sizeof(uint32_t));
    //start gpio task
    xTaskCreate(gpio_task_example, "gpio_task_example", 1024, NULL, 10, NULL);
    //install gpio isr service
    gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
    //hook isr handler for specific gpio pin
    gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler4, (void*) GPIO_INPUT_IO_0);
    gpio_isr_handler_add(GPIO_INPUT_IO_1, gpio_isr_handler7, (void*) GPIO_INPUT_IO_1);
    //gpio_set_level(GPIO_OUTPUT_IO_1, cnt % 2);
}
/** 
 *@brief 打印GPIO相关的状态，用于调试gpio
 **/
void Buttonsatus_Print(int delay)
{
    //打印GPIO4，GPIO7总共进入几次中断
        printf("enter isr IO4: %-4d    -   ",enter_isr_cnt4);
        printf(" IO7: %-4d  ,   ",enter_isr_cnt7);
    //打印按键 经过延时消抖之后究竟被按下了几次 
        printf("*------/-----*");
        printf("pin4 - %-4d  ,  ",pin4_pressed);
        printf("pin7 - %-4d    ",pin7_pressed);
        vTaskDelay(delay / portTICK_PERIOD_MS);
}


/*
    uint32_t io_num;
    int static  is_pressed=0;
    for (;;) {
        vTaskDelay(10 / portTICK_PERIOD_MS); // 等待消抖延时
        // 检查输入引脚的状态
        if (gpio_get_level(GPIO_INPUT_IO_0) != last_button_state) {
            // 如果状态发生了变化
            vTaskDelay(DEBOUNCE_DELAY_MS / portTICK_PERIOD_MS); // 等待消抖延时
            if (gpio_get_level(GPIO_INPUT_IO_0) != last_button_state) {
                // 如果延时后状态仍然没有变回原来的状态，则认为是有效的按键
                last_button_state = gpio_get_level(GPIO_INPUT_IO_0);
                is_pressed++;
                printf("-GPIO[%u] intr, val: %d-  cnt %d\n", GPIO_INPUT_IO_0, last_button_state,is_pressed);
                
            }
        }
    }
*/